package com.mrd.frame.remote;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mrd.frame.domain.AccessConfig;
import com.mrd.frame.domain.Config;
import com.mrd.frame.domain.Order;
import com.mrd.frame.domain.TradeStatement;
import com.mrd.frame.domain.WhiteListConfig;
import com.mrd.frame.domain.params.PayParams;
import com.mrd.frame.domain.params.ReconciliationParams;
import com.mrd.frame.domain.params.RefundParams;
import com.mrd.frame.service.ConfigService;
import com.mrd.frame.service.OrderService;
import com.mrd.frame.service.TradeStatementService;
import com.mrd.weixinpay.util.BeanUtil;
import com.mrd.weixinpay.util.HttpUtil;
import com.mrd.weixinpay.util.MD5Util;

/**
 * 验证请求和参数
 * @author dusy
 *
 */
@Component
public class Validate {
	
	private static Logger logger = Logger.getLogger(Validate.class);
	
	@Autowired
	private OrderService orderService;
	@Autowired
	private ConfigService configService;
	@Autowired
	private TradeStatementService tradeStatementService;
	
	/**
	 * 验证请求的有效性(参数、白名单、签名验证、退款合理性验证、支付渠道验证、请求统一性验证)
	 * @param request http请求
	 * @param params PayParams或者RefundParams
	 * @param order 商户订单号有效性验证获得的order
	 * @return PASS:验证通过
	 */
	public String validateRequest(HttpServletRequest request, Object params, Order order){
		String result = null;
		
		//参数验证
		String userKey = "";
		String tradeNo = "";
		String sign = "";
		String payChannel = "";
		if(params == null){
			return "必须传入参数对象";
		}else if((result = checkParams(params)) != null){
			return result;
		}else if(params instanceof PayParams){
			userKey = ((PayParams) params).getUserKey();
			tradeNo = ((PayParams) params).getOutTradeNo();
			sign = ((PayParams) params).getSign();
			payChannel = ((PayParams) params).getPayChannel();
		}else if(params instanceof RefundParams){
			userKey = ((RefundParams) params).getUserKey();
			tradeNo = ((RefundParams) params).getOutTradeNo();
			sign = ((RefundParams) params).getSign();
			payChannel = ((RefundParams) params).getPayChannel();
		}else {
			return "参数对象传入不正确";
		}
		
		//获取配置信息
		Config config = configService.selectByUserKey(userKey);
		List<AccessConfig> accessConfigList = config.getAccessConfigList();
		
		//支付渠道验证
		boolean havePayChannel = false;
		for(AccessConfig ac : accessConfigList){	
			if(payChannel.equals(ac.getPayChannel())){
				havePayChannel = true;
			}
		}
		if(!havePayChannel){
			return "用户还没有在平台注册该支付渠道";
		}
		
		//白名单验证
		if(!inTheWhiteList(userKey, request)){	
			return "白名单验证没通过";
		}
		
		//签名验证
		if(!sign.equals(MD5Util.getMD5(userKey + tradeNo))){
			return "签名没有通过";
		}
		
		//请求统一性验证(同一商户订单号，请求内容不能修改)
		if(isOrderChange(params, order)){
			return "订单信息不能修改";
		}
		
		//退款金额验证
		if(params instanceof RefundParams){
			TradeStatement record = new TradeStatement();
			record.setUserKey(((RefundParams) params).getUserKey());
			record.setTradeNo(((RefundParams) params).getOutTradeNo());
			List<TradeStatement> payList = tradeStatementService.selectSelective(record);
			if(payList == null || payList.size() == 0){
				return "该支付还没有完成！";
			}
			record.setTradeNo(((RefundParams) params).getOutRefundNo());
			List<TradeStatement> refundList = tradeStatementService.selectSelective(record);
			if(refundList != null){
				int totalAmount = 0;
				for(TradeStatement ts : refundList){
					totalAmount += ts.getTotalAmount();
				}
				if(totalAmount > payList.get(0).getTotalAmount()){
					return "退款金额不能大于支付金额！";
				}
			}
		}
		
		return "PASS";
	}
	
	/**
	 * 验证商户订单号的有效性（支付和退款都可以用）
	 * @return null:新的请求，roder的status代表商户订单号当前最新的状态
	 */
	public Order checkTradeNo(String userKey, String tradeNo) {
		Order record = new Order();
		record.setUserKey(userKey);
		record.setTradeNo(tradeNo);
		List<Order> orderList = orderService.selectSelective(record);
		Order returnRecord = null;
		//判断是否为新的订单
		if(orderList == null || orderList.size() == 0){
			return returnRecord;
		}
		//提取最能反映商户订单号当前状态的order
		for(Order order : orderList){
			//同一商户订单只允许存在一个已完成或进行中的order
			if("1".equals(order.getStatus()) || "2".equals(order.getStatus())){
				return order;
			} else {//预防已完成或进行中的order排在后面，遍历所有order
				if(returnRecord == null){
					returnRecord = order;
				}
			}
		}
		return returnRecord;
	}

	/**
	 * 参数验证(非空验证，长度验证)
	 * @return null则验证通过
	 */
	public String checkParams(Object o){
		try {
			Field[] fields = o.getClass().getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				String fieldName = fields[i].getName();
				//对账只要求userKey非空
				if(o instanceof ReconciliationParams){
					if(!"userKey".equals(fieldName)){
						continue;
					}
				}
				String firstLetter = fieldName.substring(0, 1).toUpperCase();
				String getter = "get" + firstLetter + fieldName.substring(1);
				Method method;
				method = o.getClass().getMethod(getter, new Class[] {});
				Object value = method.invoke(o, new Object[] {});
				if(value == null && "".equals(value)){
					return fieldName + ":参数不能为空";
				}
				if(value instanceof String 
						&& "outTradeNo outRefundNo".contains(fieldName) 
						&& ((String) value).length() > 32){
					return fieldName + ":参数长度过长";
				}
			}
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		} catch (SecurityException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
		}
		return null;
	}
	
	public boolean inTheWhiteList(String userKey,HttpServletRequest request){
		Config config = configService.selectByUserKey(userKey);
		List<WhiteListConfig> WhiteList = config.getWhiteListConfigList();
		String requestIP = HttpUtil.getIpByRequest(request);
		logger.info("请求支付IP:"+requestIP);
		boolean inTheWhiteList = false;
		for(WhiteListConfig wlc : WhiteList){
			if(requestIP.equals(wlc.getIp())){
				inTheWhiteList = true;
				break;
			}
		}
		return inTheWhiteList;
	}
	
	public boolean isOrderChange(Object params, Order oldOrder){
		if(oldOrder == null){
			return false;
		}
		return !oldOrder.equals(BeanUtil.paramsToOrder(params));
	}
}
